package com.lcf.order.controller;

import com.alibaba.fastjson.JSON;
import com.lcf.order.VO.ResultVo;
import com.lcf.order.client.ProductClient;
import com.lcf.order.entity.ProductInfo;
import com.lcf.order.utils.ResultVoUtils;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Created by lancf on 2019/7/17.
 */
@RestController
//@DefaultProperties(defaultFallback = "defaultFallback")
@Slf4j
public class HystrixController {
    @Autowired
    private ProductClient productClient;

    /**
     * hystrix有一个默认的超时时间 com.netflix.hystrix.HystrixCommandProperties中的default_executionTimeoutInMilliseconds=1000参数
     * 如果execution.isolation.thread.timeoutInMilliseconds没有设置值,就会使用默认超时时间
     *
     * @param num
     * @return
     * @throws Exception
     */
    //1. 最基本配置,调用方法,返回提前设置好的值
//    @HystrixCommand(fallbackMethod = "fallback",commandProperties = {
//            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2500")
//    })
    //2.使用默认的方法
//    @HystrixCommand

    //3 服务熔断
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),               //是否启用熔断器，默认为 true
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),    //启用熔断器功能窗口时间内的最小请求数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10"),//此配置项指定了熔断器打开后经过多长时间允许一次请求尝试执行，默认值是 5000
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "70") //在通过滑动窗口获取到当前时间段内 Hystrix 方法执行的失败率后，就需要根据此配置来判断是否要将熔断器打开了。此配置项默认值是 50
    })
    @GetMapping("/getTest")
    public ResultVo<Map<String, String>> getTest(@RequestParam("num") int num) throws Exception {

        //如果是方法里面错误会返回吗?
        //这种方式传递参数,为什么在fallback方法里也需要传递参数???
        if (num == 0) {
            throw new Exception("报错了");
        } else {
            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.postForObject("http://localhost:8001/listForOrder", Arrays.asList("111"), String.class);

            return ResultVoUtils.success(response);
        }
    }


    /**
     * feign中自带hystrix
     * @return
     */
    @GetMapping("/getTest2")
    public ResultVo<Map<String, String>> getTest2(){
        List<ProductInfo> productInfoList = productClient.productListForOrder(Arrays.asList("111"));
        log.info("调用商品服务{}", JSON.toJSONString(productInfoList));
        return ResultVoUtils.success(productInfoList);
    }

    /**
     * feign中自带hystrix
     * @return
     */
    @GetMapping("/getTest3")
    public ResultVo<Map<String, String>> getTest3(){
        String productMsg = productClient.productMsg();
        log.info("调用商品服务{}", JSON.toJSONString(productMsg));
        return ResultVoUtils.success(productMsg);
    }


    /**
     * 定制回调的方法需要带参数(与定制的controller方法参数保持一致)
     *
     * @param num
     * @return
     */
    private ResultVo<Map<String, String>> fallback(int num) {
        return ResultVoUtils.success("太拥挤了,请稍后再试");
    }

    /**
     * 默认本地回调的方法不用带参数
     *
     * @return
     */
    private ResultVo<Map<String, String>> defaultFallback() {
        return ResultVoUtils.success("默认提示: 太拥挤了,请稍后再试");
    }
}
